﻿// -----------------------------------------------------------------------
// <copyright file="Repository.cs" company="AGR">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace AGR.Data.Repository.Contract
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Linq;
    using System.Linq.Expressions;
    using System.Collections.ObjectModel;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public abstract class AbstractRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected ContextHelper _contextHelper;
        internal Context.AGRContext _context;

        #region Constuctor
        public AbstractRepository()
        { }
        #endregion

        #region Destuctor
        ~AbstractRepository()
        {
            Dispose(false);
        }
        #endregion

        #region Methods

        public IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            return GetAll().Where(predicate);
        }

        public ReadOnlyCollection<TEntity> FindByReadOnly(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            return GetAll().Where(predicate).ToList().AsReadOnly();
        }

        public TEntity FindSingleBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            try
            {
                return GetAll().Single(predicate);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public IQueryable<TEntity> FindOrderBy(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
        {
            IQueryable<TEntity> query = GetAll();

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                //query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query);
            }
            else
            {
                return query;
            }
        }

        public ReadOnlyCollection<TEntity> FindOrderByReadOnly(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
        {
            IQueryable<TEntity> query = GetAll();

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                //query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList().AsReadOnly();
            }
            else
            {
                return query.ToList().AsReadOnly();
            }
        }

        public abstract IQueryable<TEntity> GetAll();

        public ReadOnlyCollection<TEntity> GetAllReadOnly()
        {
            return GetAll().ToList().AsReadOnly();
        }

        public abstract void Add(TEntity entity);

        public abstract void Update(TEntity entity);

        public abstract void Delete(TEntity entityToDelete);

        public void DeleteBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            IQueryable<TEntity> entitiesToDelete = GetAll().Where(predicate);

            foreach (TEntity entity in entitiesToDelete)
            {
                Delete(entity);
            }
        }

        public void SaveChanges()
        {
            _context.SubmitChanges();
        }

        #endregion

        #region Dispose

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
